package sql.lexer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SQLLexer {
    private final String input;
    private int currentPosition;


    // SQL关键字映射
    private static final Map<String, TokenType> KEYWORDS = new HashMap<>();
    static {
        KEYWORDS.put(Keywords.SELECT, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.FROM, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.WHERE, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.IN, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.AS, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.INSERT, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.INTO, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.VALUES, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.UPDATE, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.SET, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.AND, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.OR, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.ORDER, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.BY, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.ASC, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.DESC, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.LIMIT, TokenType.KEYWORD);
        KEYWORDS.put(Keywords.DELETE, TokenType.KEYWORD);
    }

    public SQLLexer(String input) {
        this.input = input;
        this.currentPosition = 0;
    }

    // 获取下一个Token
    public Token nextToken() {
        // 跳过空白字符
        skipWhitespace();

        // 检查是否到达输入末尾
        if (currentPosition >= input.length()) {
            return new Token(TokenType.EOF, "");
        }

        char currentChar = input.charAt(currentPosition);

        // 处理注释
        if (currentChar == '-' && currentPosition + 1 < input.length()
                && input.charAt(currentPosition + 1) == '-') {
            skipComment();
            return nextToken(); // 递归调用处理注释后的下一个token
        }

        // 处理数字（包括负数）
        if (Character.isDigit(currentChar) ||
                (currentChar == '-' && currentPosition + 1 < input.length()
                        && Character.isDigit(input.charAt(currentPosition + 1)))) {
            return readNumber();
        }

        // 处理标识符和关键字
        if (Character.isLetter(currentChar) || currentChar == '_' || currentChar == '"') {
            return readIdentifierOrKeyword();
        }

        // 处理字符串
        if (currentChar == '\'') {
            return readString();
        }

        // 处理运算符和符号
        return readOperatorOrSymbol();
    }

    // 读取标识符或关键字
    private Token readIdentifierOrKeyword() {
        // 处理双引号标识符
        boolean quoted = false;
        if (input.charAt(currentPosition) == '"') {
            quoted = true;
            currentPosition++; // 跳过开头的双引号
        }

        int start = currentPosition;
        while (currentPosition < input.length()) {
            char c = input.charAt(currentPosition);

            // 如果是双引号标识符，允许包含空格和特殊字符
            if (quoted) {
                if (c == '"') {
                    // 结束双引号
                    String value = input.substring(start, currentPosition);
                    currentPosition++; // 跳过结束引号
                    return new Token(TokenType.IDENTIFIER, value);
                }
                currentPosition++;
                continue;
            }

            // 普通标识符
            if (!Character.isLetterOrDigit(c) && c != '_' && c != '.') {
                break;
            }
            currentPosition++;
        }

        String value = input.substring(start, currentPosition);

        // 处理双引号标识符未闭合的情况
        if (quoted) {
            return new Token(TokenType.INVALID, "\"" + value);
        }

        // 检查是否包含点号(用于table.column)
        if (value.contains(".")) {
            return new Token(TokenType.IDENTIFIER, value);
        }

        String upperValue = value.toUpperCase();
        if (KEYWORDS.containsKey(upperValue)) {
            return new Token(TokenType.KEYWORD, upperValue);
        }
        return new Token(TokenType.IDENTIFIER, value);
    }

    // 读取数字（支持负数和小数）
    private Token readNumber() {
        int start = currentPosition;
        boolean hasDecimal = false;
        boolean isNegative = false;

        // 处理负数
        if (input.charAt(currentPosition) == '-') {
            isNegative = true;
            currentPosition++;
        }
        // 处理正数（显式的+号）
        else if (input.charAt(currentPosition) == '+') {
            currentPosition++;
        }

        while (currentPosition < input.length()) {
            char c = input.charAt(currentPosition);

            if (c == '.') {
                if (hasDecimal) break; // 遇到第二个小数点，结束
                hasDecimal = true;
                currentPosition++;
            } else if (Character.isDigit(c)) {
                currentPosition++;
            } else if ((c == 'e' || c == 'E') && currentPosition + 1 < input.length()) {
                // 处理科学计数法
                char nextChar = input.charAt(currentPosition + 1);
                if (Character.isDigit(nextChar) || nextChar == '+' || nextChar == '-') {
                    currentPosition += 2;
                    continue;
                }
                break;
            } else {
                break;
            }
        }

        String value = input.substring(start, currentPosition);
        return new Token(TokenType.NUMBER, value);
    }

    // 读取字符串
    private Token readString() {
        currentPosition++; // 跳过开头的单引号
        int start = currentPosition;
        StringBuilder sb = new StringBuilder();

        while (currentPosition < input.length()) {
            char c = input.charAt(currentPosition);

            // 处理转义序列
            if (c == '\\') {
                if (currentPosition + 1 < input.length()) {
                    char nextChar = input.charAt(currentPosition + 1);
                    switch (nextChar) {
                        case 'n': sb.append('\n'); break;
                        case 't': sb.append('\t'); break;
                        case 'r': sb.append('\r'); break;
                        case '0': sb.append('\0'); break;
                        case '\'': sb.append('\''); break;
                        default: sb.append(nextChar);
                    }
                    currentPosition += 2;
                    continue;
                }
            }

            if (c == '\'') {
                // 检查是否是转义引号（两个连续引号）
                if (currentPosition + 1 < input.length() && input.charAt(currentPosition + 1) == '\'') {
                    sb.append('\'');
                    currentPosition += 2; // 跳过两个引号
                    continue;
                } else {
                    currentPosition++; // 跳过结束引号
                    return new Token(TokenType.STRING, sb.toString());
                }
            }

            sb.append(c);
            currentPosition++;
        }

        // 如果没有找到结束引号，返回无效Token
        return new Token(TokenType.INVALID, sb.toString());
    }

    // 读取运算符和符号
    private Token readOperatorOrSymbol() {
        char currentChar = input.charAt(currentPosition++);

        switch (currentChar) {
            case '=':
                if (currentPosition < input.length() && input.charAt(currentPosition) == '=') {
                    currentPosition++;
                    return new Token(TokenType.EQUALS, "==");
                }
                return new Token(TokenType.EQUALS, "=");

            case '!':
                if (currentPosition < input.length() && input.charAt(currentPosition) == '=') {
                    currentPosition++;
                    return new Token(TokenType.NOT_EQUALS, "!=");
                }
                break;

            case '<':
                if (currentPosition < input.length()) {
                    char nextChar = input.charAt(currentPosition);
                    if (nextChar == '=') {
                        currentPosition++;
                        return new Token(TokenType.LESS_EQUAL, "<=");
                    } else if (nextChar == '>') {
                        currentPosition++;
                        return new Token(TokenType.NOT_EQUALS, "<>");
                    }
                }
                return new Token(TokenType.LESS_THAN, "<");

            case '>':
                if (currentPosition < input.length() && input.charAt(currentPosition) == '=') {
                    currentPosition++;
                    return new Token(TokenType.GREATER_EQUAL, ">=");
                }
                return new Token(TokenType.GREATER_THAN, ">");

            case ',':
                return new Token(TokenType.COMMA, ",");

            case '.':
                return new Token(TokenType.DOT, ".");

            case '*':
                return new Token(TokenType.STAR, "*");

            case '(':
                return new Token(TokenType.LEFT_PAREN, "(");

            case ')':
                return new Token(TokenType.RIGHT_PAREN, ")");

            case ';':
                return new Token(TokenType.SEMICOLON, ";");

            case '-':
                return new Token(TokenType.MINUS, "-");

            case '+':
                return new Token(TokenType.PLUS, "+");
        }

        return new Token(TokenType.INVALID, String.valueOf(currentChar));
    }

    // 跳过空白字符
    private void skipWhitespace() {
        while (currentPosition < input.length()) {
            char c = input.charAt(currentPosition);
            if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
                currentPosition++;
            } else {
                break;
            }
        }
    }

    // 跳过注释
    private void skipComment() {
        // 跳过两个连续的短横线
        currentPosition += 2;

        // 继续跳过直到行尾
        while (currentPosition < input.length()) {
            char c = input.charAt(currentPosition);
            if (c == '\n' || c == '\r') {
                break;
            }
            currentPosition++;
        }
    }

    // 获取所有Token
    public List<Token> getAllTokens() {
        List<Token> tokens = new ArrayList<>();
        Token token;
        do {
            token = nextToken();
            if (token.type != TokenType.INVALID) {
                tokens.add(token);
            }
        } while (token.type != TokenType.EOF);
        return tokens;
    }
}